import os
import re
from datetime import datetime
from dotenv import load_dotenv
from flask import Flask, render_template, request, jsonify, redirect, url_for
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager, UserMixin, login_user, logout_user, login_required, current_user
from werkzeug.security import generate_password_hash, check_password_hash
from openai import OpenAI
import subprocess
from sqlalchemy import func

load_dotenv()

app = Flask(__name__)
app.config.update(
    SECRET_KEY=os.getenv("SECRET_KEY", "dev-secret-key"),
    SQLALCHEMY_DATABASE_URI='sqlite:///site.db',
    SQLALCHEMY_TRACK_MODIFICATIONS=False,
    DEEPSEEK_API_KEY="sk-2e01e7874faa4c52a967b6b5bbc49251",
    DEEPSEEK_BASE_URL='https://api.deepseek.com'
)

db = SQLAlchemy(app)
login_manager = LoginManager(app)
login_manager.login_view = 'login'

deepseek_client = OpenAI(
    api_key=app.config['DEEPSEEK_API_KEY'],
    base_url=app.config['DEEPSEEK_BASE_URL']
)

# 数据库模型
class Task(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    teacher_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
    class_id = db.Column(db.String(20), nullable=False)
    title = db.Column(db.String(100), nullable=False)
    content = db.Column(db.Text, nullable=False)
    created_at = db.Column(db.DateTime, default=datetime.utcnow)
    deadline = db.Column(db.DateTime)
    teacher = db.relationship('User', backref=db.backref('tasks', lazy='dynamic'))

class User(db.Model, UserMixin):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(20), unique=True, nullable=False)
    password = db.Column(db.String(100), nullable=False)
    role = db.Column(db.String(10), nullable=False)  # teacher/student/parent
    student_id = db.Column(db.Integer, db.ForeignKey('user.id'))
    class_id = db.Column(db.String(20))
    student = db.relationship('User', remote_side=[id], backref='parents')

class CodeHistory(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
    task_id = db.Column(db.Integer, db.ForeignKey('task.id'), nullable=True)
    code_content = db.Column(db.Text, nullable=False)
    score = db.Column(db.Float)
    timestamp = db.Column(db.DateTime, default=datetime.utcnow)
    user = db.relationship('User', backref=db.backref('histories', lazy='select'))
    task = db.relationship('Task', backref=db.backref('histories', lazy='dynamic'))

class TeacherRating(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    teacher_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
    student_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
    rating = db.Column(db.Integer)
    comment = db.Column(db.Text)
    timestamp = db.Column(db.DateTime, default=datetime.utcnow)

@login_manager.user_loader
def load_user(user_id):
    return User.query.get(int(user_id))

# 工具函数
def analyze_with_pylint(code):
    try:
        cleaned_code = re.sub(r'\r', '', code)
        with open('temp.py', 'w', encoding='utf-8', newline='\n') as f:
            f.write(cleaned_code)
            
        result = subprocess.run(
            ['pylint', '--reports=n', 'temp.py'],
            capture_output=True,
            text=True
        )
        os.remove('temp.py')
        
        output = result.stdout
        score_match = re.search(r'rated at (\d+\.?\d*)/10', output)
        score = float(score_match.group(1)) if score_match else 0.0
        
        return {'output': output, 'score': score}
    except Exception as e:
        return {'output': f"静态分析错误: {str(e)}", 'score': 0.0}

def get_ai_feedback(code, error):
    prompt = f"""作为编程导师，请用简单易懂的中文解释以下Python代码问题：

【学生代码】
{code}

【检查结果】
{error}
（严格按下列格式回答）
问题描述（出现在哪一行）
解决步骤（分步骤说明）
正确示例:
请在这里给出正确示例（纯代码即可不要注释）"""
    try:
        response = deepseek_client.chat.completions.create(
            model="deepseek-chat",
            messages=[
                {"role": "system", "content": "你是一个耐心的小学编程老师，擅长用比喻解释编程概念，回答简洁不超过200字"},
                {"role": "user", "content": prompt}
            ],
            temperature=0.3,
            max_tokens=512
        )
        return response.choices[0].message.content
    except Exception as e:
        print(f"AI反馈错误: {str(e)}")
        return "AI建议暂时不可用"

# 路由配置
@app.route('/')
@login_required
def home():
    if current_user.role == 'teacher':
        return redirect(url_for('teacher_dashboard'))
    elif current_user.role == 'parent':
        return redirect(url_for('parent_dashboard'))
    return render_template('editor.html')

@app.route('/teacher_dashboard')
@login_required
def teacher_dashboard():
    if current_user.role != 'teacher':
        return redirect(url_for('home'))
    return render_template('teacher_dashboard.html')

@app.route('/create_task', methods=['GET', 'POST'])
@login_required
def create_task():
    if current_user.role != 'teacher':
        return redirect(url_for('home'))
    
    if request.method == 'POST':
        title = request.form['title']
        content = request.form['content']
        deadline_str = request.form['deadline']
        
        try:
            deadline = datetime.strptime(deadline_str, '%Y-%m-%dT%H:%M')
        except ValueError:
            return render_template('create_task.html', error='无效的日期格式')
        
        new_task = Task(
            teacher_id=current_user.id,
            class_id=current_user.class_id,
            title=title,
            content=content,
            deadline=deadline
        )
        
        try:
            db.session.add(new_task)
            db.session.commit()
            return redirect(url_for('teacher_dashboard'))
        except Exception as e:
            db.session.rollback()
            return render_template('create_task.html', error=f'保存失败: {str(e)}')
    
    return render_template('create_task.html')

@app.route('/api/tasks')
@login_required
def get_class_tasks():
    if current_user.role != 'teacher':
        return jsonify({'error': 'Unauthorized'}), 403
    
    tasks = Task.query.filter_by(
        class_id=current_user.class_id
    ).order_by(Task.created_at.desc()).all()
    
    return jsonify([{
        'id': t.id,
        'title': t.title,
        'content': t.content,
        'deadline': t.deadline.strftime('%Y-%m-%d %H:%M'),
        'created_at': t.created_at.strftime('%Y-%m-%d')
    } for t in tasks])

@app.route('/parent_dashboard')
@login_required
def parent_dashboard():
    if current_user.role != 'parent' or not current_user.student_id:
        return redirect(url_for('home'))
    
    student = User.query.options(db.joinedload(User.histories)).get(current_user.student_id)
    if not student:
        return redirect(url_for('home'))
    
    avg_score = 0.0
    if student.histories:
        total = sum(history.score for history in student.histories)
        avg_score = round(total / len(student.histories), 1)
    
    latest_rating = TeacherRating.query.filter_by(
        student_id=student.id
    ).order_by(TeacherRating.timestamp.desc()).first()
    
    return render_template(
        'parent_dashboard.html',
        student=student,
        avg_score=avg_score,
        latest_rating=latest_rating
    )

@app.route('/history')
@login_required
def history_page():
    if current_user.role == 'teacher':
        return redirect(url_for('teacher_dashboard'))
    elif current_user.role == 'parent':
        return redirect(url_for('parent_dashboard'))
    return render_template('history.html')

@app.route('/api/student/tasks')
@login_required
def get_student_tasks():
    if current_user.role != 'student' or not current_user.class_id:
        return jsonify({'error': '无权访问'}), 403
    
    tasks = Task.query.filter_by(
        class_id=current_user.class_id
    ).order_by(Task.deadline.asc()).all()
    
    return jsonify([{
        'id': t.id,
        'title': t.title,
        'content': t.content,
        'deadline': t.deadline.isoformat(),
        'created_at': t.created_at.isoformat()
    } for t in tasks])

@app.route('/api/tasks/<int:task_id>')
@login_required
def get_task_detail(task_id):
    task = Task.query.get_or_404(task_id)
    if current_user.role == 'student' and task.class_id != current_user.class_id:
        return jsonify({'error': '无权访问'}), 403
    
    return jsonify({
        'title': task.title,
        'content': task.content,
        'deadline': task.deadline.isoformat(),
        'created_at': task.created_at.isoformat()
    })

@app.route('/api/tasks/<int:task_id>/histories')
@login_required
def get_task_histories(task_id):
    task = Task.query.get_or_404(task_id)
    if current_user.role == 'student' and task.class_id != current_user.class_id:
        return jsonify({'error': '无权访问'}), 403
    
    histories = CodeHistory.query.filter_by(
        user_id=current_user.id,
        task_id=task_id
    ).order_by(CodeHistory.timestamp.desc()).all()
    
    return jsonify([{
        'id': h.id,
        'score': h.score,
        'timestamp': h.timestamp.strftime('%Y-%m-%d %H:%M:%S'),
        'preview': h.code_content[:50] + ('...' if len(h.code_content) > 50 else '')
    } for h in histories])

@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        username = request.form['username']
        password = request.form['password']
        role = request.form['role']
        
        user = User.query.filter_by(username=username, role=role).first()
        if user and check_password_hash(user.password, password):
            login_user(user)
            next_page = 'teacher_dashboard' if user.role == 'teacher' else \
                        'parent_dashboard' if user.role == 'parent' else 'home'
            return redirect(url_for(next_page))
        return render_template('login.html', error='用户名或密码错误')
    return render_template('login.html')

@app.route('/register', methods=['GET', 'POST'])
def register():
    if request.method == 'POST':
        username = request.form['username']
        password = generate_password_hash(request.form['password'])
        role = request.form['role']
        
        if User.query.filter_by(username=username).first():
            return render_template('register.html', error='用户名已存在')
        
        new_user = User(
            username=username,
            password=password,
            role=role
        )
        
        if role == 'student':
            class_id = request.form.get('student_class_id', '').strip()
            if not class_id:
                return render_template('register.html', error='学生必须填写班级编号')
            new_user.class_id = class_id
            
        elif role == 'teacher':
            class_id = request.form.get('teacher_class_id', '').strip()
            if not class_id:
                return render_template('register.html', error='教师必须填写班级编号')
            new_user.class_id = class_id

        elif role == 'parent':
            student_username = request.form.get('student_username')
            student = User.query.filter_by(username=student_username, role='student').first()
            if not student:
                return render_template('register.html', error='关联学生不存在')
            new_user.student_id = student.id
        
        try:
            db.session.add(new_user)
            db.session.commit()
            return redirect(url_for('login'))
        except Exception as e:
            db.session.rollback()
            return render_template('register.html', error=f'注册失败: {str(e)}')
    
    return render_template('register.html')

@app.route('/analyze', methods=['POST'])
@login_required
def analyze():
    code = request.form.get('code', '')
    task_id = request.form.get('task_id')
    analysis = analyze_with_pylint(code)
    
    history = CodeHistory(
        user_id=current_user.id,
        task_id=task_id,
        code_content=code,
        score=analysis['score']
    )
    
    try:
        db.session.add(history)
        db.session.commit()
    except Exception as e:
        db.session.rollback()
        app.logger.error(f'保存失败: {str(e)}')
    
    ai_feedback = get_ai_feedback(code, analysis['output']) if analysis['output'] else ""
    
    return jsonify({
        'pylint': analysis['output'],
        'ai_feedback': ai_feedback,
        'score': analysis['score']
    })

@app.route('/api/students')
@login_required
def get_class_students():
    try:
        if current_user.role != 'teacher':
            return jsonify({'error': 'Unauthorized access'}), 403
        
        students = User.query.filter_by(
            role='student',
            class_id=current_user.class_id
        ).options(db.joinedload(User.histories)).all()
        
        student_data = []
        for s in students:
            avg_score = 0
            if s.histories:
                total = sum(h.score for h in s.histories)
                avg_score = round(total / len(s.histories), 1)
                
            student_data.append({
                'id': s.id,
                'username': s.username,
                'class_id': s.class_id,
                'last_submission': s.histories[-1].timestamp.isoformat() if s.histories else None,
                'avg_score': avg_score
            })
        
        return jsonify(student_data)
    
    except Exception as e:
        app.logger.error(f'Error in get_class_students: {str(e)}')
        return jsonify({'error': 'Internal server error'}), 500

@app.after_request
def set_content_type(response):
    if request.path.startswith('/api/'):
        response.headers['Content-Type'] = 'application/json'
    return response

@app.route('/api/history')
@login_required
def get_user_history():
    try:
        start_date = request.args.get('start_date')
        end_date = request.args.get('end_date')
        
        query = CodeHistory.query.filter_by(user_id=current_user.id)
        
        if start_date:
            start = datetime.strptime(start_date, '%Y-%m-%d')
            query = query.filter(CodeHistory.timestamp >= start)
        if end_date:
            end = datetime.strptime(end_date, '%Y-%m-%d').replace(hour=23, minute=59, second=59)
            query = query.filter(CodeHistory.timestamp <= end)
        
        histories = query.order_by(CodeHistory.timestamp.desc()).all()
        
        return jsonify([{
            'id': h.id,
            'score': h.score,
            'timestamp': h.timestamp.strftime('%Y-%m-%d %H:%M:%S'),
            'preview': h.code_content[:50] + ('...' if len(h.code_content) > 50 else '')
        } for h in histories])
    
    except ValueError:
        return jsonify({'error': '无效的日期格式'}), 400
    except Exception as e:
        app.logger.error(f'获取历史记录失败: {str(e)}')
        return jsonify({'error': '服务器内部错误'}), 500
    
@app.route('/api/history/<int:history_id>')
@login_required
def get_history_detail(history_id):
    history = CodeHistory.query.filter_by(
        id=history_id,
        user_id=current_user.id
    ).first_or_404()
    
    return jsonify({
        'code': history.code_content,
        'score': history.score,
        'timestamp': history.timestamp.strftime('%Y-%m-%d %H:%M:%S')
    })

@app.route('/api/student/<int:student_id>')
@login_required
def get_student_detail(student_id):
    if current_user.role != 'teacher':
        return jsonify({'error': '无权访问'}), 403
    
    student = User.query.get_or_404(student_id)
    if student.class_id != current_user.class_id:
        return jsonify({'error': '无权访问'}), 403
    
    rating = TeacherRating.query.filter_by(
        teacher_id=current_user.id,
        student_id=student_id
    ).first()
    
    return jsonify({
        'username': student.username,
        'history': [{
            'id': h.id,
            'timestamp': h.timestamp.isoformat(),
            'score': h.score,
            'code_content': h.code_content[:200] + '...'
        } for h in student.histories],
        'rating': {
            'rating': rating.rating if rating else None,
            'comment': rating.comment if rating else None
        }
    })

@app.route('/api/rate/<int:student_id>', methods=['POST'])
@login_required
def rate_student(student_id):
    if current_user.role != 'teacher':
        return jsonify({'error': '无权操作'}), 403
    
    data = request.get_json()
    rating = TeacherRating(
        teacher_id=current_user.id,
        student_id=student_id,
        rating=data.get('rating'),
        comment=data.get('comment', '')
    )
    
    try:
        db.session.merge(rating)
        db.session.commit()
        return jsonify({'success': True})
    except Exception as e:
        db.session.rollback()
        return jsonify({'error': str(e)}), 500

@app.route('/logout')
@login_required
def logout():
    logout_user()
    return redirect(url_for('login'))

if __name__ == '__main__':
    with app.app_context():
        db.create_all()
    app.run(debug=os.getenv('FLASK_DEBUG', False))